y + height <= global.screen_height;
}
- _onScreenshotComplete(result, area, filenameUsed, flash, invocation) {
+ *_resolveRelativeFilename(filename) {
+ if (GLib.str_has_suffix(filename, '.png'))
+ filename = filename.substr(0, -4);
+
+ let path = [
+ GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES),
+ GLib.get_home_dir(),
+ ].find(p => GLib.file_test(p, GLib.FileTest.EXISTS));
+
+ if (!path)
+ return null;
+
+ yield Gio.File.new_for_path(
+ GLib.build_filenamev([path, `${filename}.png`]));
+
+ for (let idx = 1; ; idx++) {
+ yield Gio.File.new_for_path(
+ GLib.build_filenamev([path, `${filename}-${idx}.png`]));
+ }
+ }
+
+ _createStream(filename) {
+ if (GLib.path_is_absolute(filename)) {
+ try {
+ let file = Gio.File.new_for_path(filename);
+ let stream = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
+ return [stream, file];
+ } catch (e) {
+ return [null, null];
+ }
+ }
+
+ for (let file of this._resolveRelativeFilename(filename)) {
+ try {
+ let stream = file.create(Gio.FileCreateFlags.NONE, null);
+ return [stream, file];
+ } catch (e) {
+ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS))
+ return [null, null];
+ }
+ }
+
+ return [null, null];
+ }
+
+ _onScreenshotComplete(result, area, stream, file, flash, invocation) {
if (result) {
if (flash) {
let flashspot = new Flashspot(area);
}
}
+ stream.close(null);
+
+ let filenameUsed = file.get_path();
let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
invocation.return_value(retval);
}
let screenshot = this._createScreenshot(invocation);
if (!screenshot)
return;
- screenshot.screenshot_area (x, y, width, height, filename,
+
+ let [stream, file] = this._createStream(filename);
+
+ screenshot.screenshot_area (x, y, width, height, stream,
(o, res) => {
try {
- let [result, area, filenameUsed] =
+ let [result, area] =
screenshot.screenshot_area_finish(res);
this._onScreenshotComplete(
- result, area, filenameUsed, flash, invocation);
+ result, area, stream, file, flash, invocation);
} catch (e) {
invocation.return_gerror (e);
}
let screenshot = this._createScreenshot(invocation);
if (!screenshot)
return;
- screenshot.screenshot_window (includeFrame, includeCursor, filename,
+
+ let [stream, file] = this._createStream(filename);
+
+ screenshot.screenshot_window (includeFrame, includeCursor, stream,
(o, res) => {
try {
- let [result, area, filenameUsed] =
+ let [result, area] =
screenshot.screenshot_window_finish(res);
this._onScreenshotComplete(
- result, area, filenameUsed, flash, invocation);
+ result, area, stream, file, flash, invocation);
} catch (e) {
invocation.return_gerror (e);
}
let screenshot = this._createScreenshot(invocation);
if (!screenshot)
return;
- screenshot.screenshot(includeCursor, filename,
+
+ let [stream, file] = this._createStream(filename);
+
+ screenshot.screenshot(includeCursor, stream,
(o, res) => {
try {
- let [result, area, filenameUsed] =
+ let [result, area] =
screenshot.screenshot_finish(res);
this._onScreenshotComplete(
- result, area, filenameUsed, flash, invocation);
+ result, area, stream, file, flash, invocation);
} catch (e) {
invocation.return_gerror (e);
}
{
ShellGlobal *global;
- char *filename;
- char *filename_used;
+ GOutputStream *stream;
GDateTime *datetime;
g_object_unref (result);
g_clear_pointer (&priv->image, cairo_surface_destroy);
- g_clear_pointer (&priv->filename, g_free);
- g_clear_pointer (&priv->filename_used, g_free);
+ g_clear_object (&priv->stream);
g_clear_pointer (&priv->datetime, g_date_time_unref);
meta_enable_unredirect_for_display (shell_global_get_display (priv->global));
}
-/* called in an I/O thread */
-static GOutputStream *
-get_stream_for_unique_path (const gchar *path,
- const gchar *filename,
- gchar **filename_used)
-{
- GOutputStream *stream;
- GFile *file;
- gchar *real_path, *real_filename, *name, *ptr;
- gint idx;
-
- ptr = g_strrstr (filename, ".png");
-
- if (ptr != NULL)
- real_filename = g_strndup (filename, ptr - filename);
- else
- real_filename = g_strdup (filename);
-
- idx = 0;
- real_path = NULL;
-
- do
- {
- if (idx == 0)
- name = g_strdup_printf ("%s.png", real_filename);
- else
- name = g_strdup_printf ("%s - %d.png", real_filename, idx);
-
- real_path = g_build_filename (path, name, NULL);
- g_free (name);
-
- file = g_file_new_for_path (real_path);
- stream = G_OUTPUT_STREAM (g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL));
- g_object_unref (file);
-
- if (stream != NULL)
- *filename_used = real_path;
- else
- g_free (real_path);
-
- idx++;
- }
- while (stream == NULL);
-
- g_free (real_filename);
-
- return stream;
-}
-
-/* called in an I/O thread */
-static GOutputStream *
-get_stream_for_filename (const gchar *filename,
- gchar **filename_used)
-{
- const gchar *path;
-
- path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
- if (!g_file_test (path, G_FILE_TEST_EXISTS))
- {
- path = g_get_home_dir ();
- if (!g_file_test (path, G_FILE_TEST_EXISTS))
- return NULL;
- }
-
- return get_stream_for_unique_path (path, filename, filename_used);
-}
-
-static GOutputStream *
-prepare_write_stream (const gchar *filename,
- gchar **filename_used)
-{
- GOutputStream *stream;
- GFile *file;
-
- if (g_path_is_absolute (filename))
- {
- file = g_file_new_for_path (filename);
- *filename_used = g_strdup (filename);
- stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL));
- g_object_unref (file);
- }
- else
- {
- stream = get_stream_for_filename (filename, filename_used);
- }
-
- return stream;
-}
-
static void
write_screenshot_thread (GTask *result,
gpointer object,
priv = screenshot->priv;
- stream = prepare_write_stream (priv->filename,
- &priv->filename_used);
+ stream = g_object_ref (priv->stream);
if (stream == NULL)
status = CAIRO_STATUS_FILE_NOT_FOUND;
finish_screenshot (ShellScreenshot *screenshot,
GAsyncResult *result,
cairo_rectangle_int_t **area,
- const char **filename_used,
GError **error)
{
ShellScreenshotPrivate *priv = screenshot->priv;
if (area)
*area = &priv->screenshot_area;
- if (filename_used)
- *filename_used = priv->filename_used;
-
return TRUE;
}
* shell_screenshot_screenshot:
* @screenshot: the #ShellScreenshot
* @include_cursor: Whether to include the cursor or not
- * @filename: The filename for the screenshot
+ * @stream: The stream for the screenshot
* @callback: (scope async): function to call returning success or failure
* of the async grabbing
* @user_data: the data to pass to callback function
*
* Takes a screenshot of the whole screen
- * in @filename as png image.
+ * in @stream as png image.
*
*/
void
shell_screenshot_screenshot (ShellScreenshot *screenshot,
gboolean include_cursor,
- const char *filename,
+ GOutputStream *stream,
GAsyncReadyCallback callback,
gpointer user_data)
{
const char *paint_signal;
GTask *result;
- if (priv->filename != NULL) {
+ if (priv->stream != NULL) {
if (callback)
g_task_report_new_error (screenshot,
callback,
result = g_task_new (screenshot, NULL, callback, user_data);
g_task_set_source_tag (result, shell_screenshot_screenshot);
- priv->filename = g_strdup (filename);
+ priv->stream = g_object_ref (stream);
priv->include_cursor = FALSE;
stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
* @screenshot: the #ShellScreenshot
* @result: the #GAsyncResult that was provided to the callback
* @area: (out) (transfer none): the area that was grabbed in screen coordinates
- * @filename_used: (out) (transfer none): the name of the file the screenshot
- * was written to
* @error: #GError for error reporting
*
* Finish the asynchronous operation started by shell_screenshot_screenshot()
shell_screenshot_screenshot_finish (ShellScreenshot *screenshot,
GAsyncResult *result,
cairo_rectangle_int_t **area,
- const char **filename_used,
GError **error)
{
g_return_val_if_fail (g_async_result_is_tagged (result,
shell_screenshot_screenshot),
FALSE);
- return finish_screenshot (screenshot, result, area, filename_used, error);
+ return finish_screenshot (screenshot, result, area, error);
}
/**
* @y: The Y coordinate of the area
* @width: The width of the area
* @height: The height of the area
- * @filename: The filename for the screenshot
+ * @stream: The stream for the screenshot
* @callback: (scope async): function to call returning success or failure
* of the async grabbing
* @user_data: the data to pass to callback function
*
* Takes a screenshot of the passed in area and saves it
- * in @filename as png image.
+ * in @stream as png image.
*
*/
void
int y,
int width,
int height,
- const char *filename,
+ GOutputStream *stream,
GAsyncReadyCallback callback,
gpointer user_data)
{
ShellScreenshotPrivate *priv = screenshot->priv;
GTask *result;
- if (priv->filename != NULL) {
+ if (priv->stream != NULL) {
if (callback)
g_task_report_new_error (screenshot,
callback,
result = g_task_new (screenshot, NULL, callback, user_data);
g_task_set_source_tag (result, shell_screenshot_screenshot_area);
- priv->filename = g_strdup (filename);
+ priv->stream = g_object_ref (stream);
priv->screenshot_area.x = x;
priv->screenshot_area.y = y;
priv->screenshot_area.width = width;
* @screenshot: the #ShellScreenshot
* @result: the #GAsyncResult that was provided to the callback
* @area: (out) (transfer none): the area that was grabbed in screen coordinates
- * @filename_used: (out) (transfer none): the name of the file the screenshot
- * was written to
* @error: #GError for error reporting
*
* Finish the asynchronous operation started by shell_screenshot_screenshot_area()
shell_screenshot_screenshot_area_finish (ShellScreenshot *screenshot,
GAsyncResult *result,
cairo_rectangle_int_t **area,
- const char **filename_used,
GError **error)
{
g_return_val_if_fail (g_async_result_is_tagged (result,
shell_screenshot_screenshot_area),
FALSE);
- return finish_screenshot (screenshot, result, area, filename_used, error);
+ return finish_screenshot (screenshot, result, area, error);
}
/**
* @screenshot: the #ShellScreenshot
* @include_frame: Whether to include the frame or not
* @include_cursor: Whether to include the cursor or not
- * @filename: The filename for the screenshot
+ * @stream: The stream for the screenshot
* @callback: (scope async): function to call returning success or failure
* of the async grabbing
* @user_data: the data to pass to callback function
*
* Takes a screenshot of the focused window (optionally omitting the frame)
- * in @filename as png image.
+ * in @stream as png image.
*
*/
void
shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
gboolean include_frame,
gboolean include_cursor,
- const char *filename,
+ GOutputStream *stream,
GAsyncReadyCallback callback,
gpointer user_data)
{
MetaWindow *window = meta_display_get_focus_window (display);
GTask *result;
- if (priv->filename != NULL || !window) {
+ if (priv->stream != NULL || !window) {
if (callback)
g_task_report_new_error (screenshot,
callback,
result = g_task_new (screenshot, NULL, callback, user_data);
g_task_set_source_tag (result, shell_screenshot_screenshot_window);
- priv->filename = g_strdup (filename);
+ priv->stream = g_object_ref (stream);
priv->include_frame = include_frame;
priv->include_cursor = include_cursor &&
should_draw_cursor_image (SHELL_SCREENSHOT_WINDOW);
* @screenshot: the #ShellScreenshot
* @result: the #GAsyncResult that was provided to the callback
* @area: (out) (transfer none): the area that was grabbed in screen coordinates
- * @filename_used: (out) (transfer none): the name of the file the screenshot
- * was written to
* @error: #GError for error reporting
*
* Finish the asynchronous operation started by shell_screenshot_screenshot_window()
shell_screenshot_screenshot_window_finish (ShellScreenshot *screenshot,
GAsyncResult *result,
cairo_rectangle_int_t **area,
- const char **filename_used,
GError **error)
{
g_return_val_if_fail (g_async_result_is_tagged (result,
shell_screenshot_screenshot_window),
FALSE);
- return finish_screenshot (screenshot, result, area, filename_used, error);
+ return finish_screenshot (screenshot, result, area, error);
}
/**